package com.ruihu.admin.module.business.tasknode.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ruihu.admin.common.anno.MethodLog;
import com.ruihu.admin.common.constant.GlobalConst;
import com.ruihu.admin.common.constant.JudgeEnum;
import com.ruihu.admin.common.constant.ResponseCodeConst;
import com.ruihu.admin.common.domain.ResponseDTO;
import com.ruihu.admin.common.exception.BusinessException;
import com.ruihu.admin.constant.CommonConst;
import com.ruihu.admin.constant.PatternCache;
import com.ruihu.admin.module.business.electric.config.domain.dto.ElectricConfigDTO;
import com.ruihu.admin.module.business.electric.config.service.CellTypeConfigService;
import com.ruihu.admin.module.business.electric.config.service.FactoryConfigService;
import com.ruihu.admin.module.business.log.interfacelog.constant.InterfaceModuleEnum;
import com.ruihu.admin.module.business.log.interfacelog.dao.InterfaceLogDao;
import com.ruihu.admin.module.business.log.interfacelog.domain.dto.InterfaceLogQueryDTO;
import com.ruihu.admin.module.business.log.interfacelog.domain.entity.InterfaceLogEntity;
import com.ruihu.admin.module.business.node.config.dao.TaskProcessConfigDao;
import com.ruihu.admin.module.business.node.config.domain.dto.TaskProcessConfigQueryDTO;
import com.ruihu.admin.module.business.task.constant.TaskResponseCodeConst;
import com.ruihu.admin.module.business.task.constant.TaskStatusEnum;
import com.ruihu.admin.module.business.task.dao.SubTaskDao;
import com.ruihu.admin.module.business.task.dao.TaskNodeInstDao;
import com.ruihu.admin.module.business.task.domain.dto.TaskNodeInstQueryDTO;
import com.ruihu.admin.module.business.task.domain.entity.SubTaskEntity;
import com.ruihu.admin.module.business.task.domain.entity.TaskNodeInstEntity;
import com.ruihu.admin.module.business.task.manager.SubTaskManager;
import com.ruihu.admin.module.business.tasknode.constant.TaskNodeActionEnum;
import com.ruihu.admin.module.business.tasknode.converter.TaskNodeFileList;
import com.ruihu.admin.module.business.tasknode.dao.*;
import com.ruihu.admin.module.business.tasknode.domain.TaskNodeInst;
import com.ruihu.admin.module.business.tasknode.domain.TaskNodeInstFactory;
import com.ruihu.admin.module.business.tasknode.domain.dto.*;
import com.ruihu.admin.module.business.tasknode.domain.entity.NodeInstProcessRelationEntity;
import com.ruihu.admin.module.business.tasknode.domain.entity.SubTaskNodeInstEntity;
import com.ruihu.admin.module.business.tasknode.domain.vo.*;
import com.ruihu.admin.module.business.tasknode.manager.TaskNodeFileManager;
import com.ruihu.admin.module.business.tasknode.manager.TaskNodeInstManager;
import com.ruihu.admin.module.support.file.constant.FileModuleTypeEnum;
import com.ruihu.admin.module.support.file.constant.FileServiceTypeEnum;
import com.ruihu.admin.module.support.file.constant.FileSourceEnum;
import com.ruihu.admin.module.support.file.service.FileService;
import com.ruihu.admin.module.support.task.domain.AIImageDescDTO;
import com.ruihu.admin.module.support.task.domain.AIImageDescResultDTO;
import com.ruihu.admin.module.system.department.DepartmentService;
import com.ruihu.admin.module.system.department.domain.vo.DepartmentVO;
import com.ruihu.admin.module.system.user.UserService;
import com.ruihu.admin.module.system.user.domain.bo.UserBO;
import com.ruihu.admin.third.ApplicationContext;
import com.ruihu.admin.util.BaseEnumUtil;
import com.ruihu.admin.util.RequestTokenUtil;
import com.ruihu.admin.util.RhSetUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * [ 子任务环节实例表 ]
 *
 * @author Tony
 * @version 1.0
 * @company 瑞虎（南京）信息技术有限公司
 * @copyright (c)  瑞虎（南京）信息技术有限公司Inc. All rights reserved.
 * @date 2022-08-30 19:43:58
 * @since JDK1.8
 */
@Service
@Slf4j
public class SubTaskNodeInstService {

    @Autowired
    private SubTaskDao subTaskDao;

    @Autowired
    private SubTaskNodeInstDao subTaskNodeInstDao;

    @Autowired
    private TaskNodeFileDao taskNodeFileDao;

    @Autowired
    private TaskNodeInstDao taskNodeInstDao;

    @Autowired
    private NodeInstProcessRelationDao nodeInstProcessRelationDao;

    @Autowired
    private NodeInstProcessDefectDao nodeInstProcessDefectDao;

    @Autowired
    private DefectTypeDao defectTypeDao;

    @Autowired
    private TaskNodeInstManager taskNodeInstManager;

    @Autowired
    private TaskProcessConfigDao taskProcessConfigDao;

    @Autowired
    private FileService fileService;

    @Autowired
    private UserService userService;

    @Autowired
    private CellTypeConfigService cellTypeConfigService;

    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private InterfaceLogDao interfaceLogDao;

    @Autowired
    private SubTaskManager subTaskManager;

    @Autowired
    private AIInterfaceService aiInterfaceService;

    @Autowired
    private TaskNodeFileManager taskNodeFileManager;

    @Autowired
    private NodeInstProcessDefectService nodeInstProcessDefectService;

    @Autowired
    private NodeInstProcessRelationService nodeInstProcessRelationService;

    @Autowired
    private FactoryConfigService factoryConfigService;

    @Autowired
    private SetOperations<String, Object> setOperations;

    @Value("${file-upload-service.path}")
    private String fileBasePath;

    /**
     * 根据id查询
     */
    public SubTaskNodeInstEntity getById(Long id){
        return  subTaskNodeInstDao.selectById(id);
    }


    /**
     * 根据子任务ID和任务环节实例ID查询任务环节数据
     * @param subTaskId
     * @param taskNodeInstId
     * @return
     */
    @MethodLog
    public ResponseDTO<SubTaskNodeInstVO> queryTaskNodeInstData(Long subTaskId, Long taskNodeInstId) {
        SubTaskNodeInstDTO subTaskNodeInstDTO = this.subTaskNodeInstDao.querySubTaskNodeInstByTaskNodeInstId(subTaskId, taskNodeInstId);
        if (Objects.nonNull(subTaskNodeInstDTO)) {
            SubTaskNodeInstVO subTaskNodeInstVO = SubTaskNodeInstVO.convertToSubTaskNodeInstVO(subTaskNodeInstDTO);
            // 查询缺陷列表
            NodeInstProcessDefectQueryDTO queryDTO = new NodeInstProcessDefectQueryDTO();
            queryDTO.setSubTaskId(subTaskId);
            queryDTO.setTaskNodeInstId(taskNodeInstId);
            queryDTO.setProcessRelationIdIsNull(JudgeEnum.YES.getValue());
            List<NodeInstProcessDefectDTO> nodeInstProcessDefectList = this.nodeInstProcessDefectDao.queryByList(queryDTO);
            if (CollectionUtil.isNotEmpty(nodeInstProcessDefectList)) {
                List<DefectTypeVO> defectTypeVOList = new ArrayList<>(nodeInstProcessDefectList.size());
                nodeInstProcessDefectList.forEach(e -> {
                    DefectTypeVO defectTypeVO = new DefectTypeVO();
                    defectTypeVO.setTaskNodeId(subTaskNodeInstDTO.getTaskNodeId());
                    defectTypeVO.setTaskNodeName(subTaskNodeInstVO.getTaskNodeName());
                    defectTypeVO.setDefectTypeId(e.getDefectTypeId());
                    defectTypeVO.setDefectName(e.getDefectName());
                    defectTypeVOList.add(defectTypeVO);
                });
                subTaskNodeInstVO.setDefectTypeList(defectTypeVOList);
            }

            if (Objects.nonNull(subTaskNodeInstDTO.getCreateBy())) {
                UserBO createUser = this.userService.getById(subTaskNodeInstDTO.getCreateBy());
                if (Objects.nonNull(createUser)) {
                    subTaskNodeInstVO.setCreateByName(createUser.getActualName());
                }
            }

            if (Objects.nonNull(subTaskNodeInstDTO.getTaskOwner())) {
                UserBO user = this.userService.getById(subTaskNodeInstDTO.getTaskOwner());
                if (Objects.nonNull(user)) {
                    subTaskNodeInstVO.setTaskOwner(user.getActualName());
                    ResponseDTO<DepartmentVO> resp = this.departmentService.getDepartmentById(user.getDepartmentId());
                    if (resp.isSuccess()) {
                        subTaskNodeInstVO.setTaskDepartment(resp.getData().getDepartmentName());
                    }
                }
            }

            if (StrUtil.isNotEmpty(subTaskNodeInstDTO.getCellTypeCode())) {
                ResponseDTO<ElectricConfigDTO> electricConfigResp = this.cellTypeConfigService.getCellTypeConfigByCode(subTaskNodeInstDTO.getCellTypeCode());
                if (electricConfigResp.getData() != null) {
                    subTaskNodeInstVO.setCellTypeName(electricConfigResp.getData().getType());
                }
            }

            if (StrUtil.isNotEmpty(subTaskNodeInstDTO.getFactoryCode())) {
                ResponseDTO<ElectricConfigDTO> factoryResp = this.factoryConfigService.getFactoryConfigByCode(subTaskNodeInstDTO.getFactoryCode());
                if (factoryResp.isSuccess()) {
                    subTaskNodeInstVO.setFactoryName(factoryResp.getData().getType());
                }
            }

            NodeInstConfigValueQueryDTO nodeInstConfigValueQueryDTO = new NodeInstConfigValueQueryDTO();
            nodeInstConfigValueQueryDTO.setSubTaskId(subTaskId);
            nodeInstConfigValueQueryDTO.setTaskNodeId(subTaskNodeInstDTO.getTaskNodeId());
            nodeInstConfigValueQueryDTO.setTaskNodeInstId(subTaskNodeInstDTO.getTaskNodeInstId());
            nodeInstConfigValueQueryDTO.setSubTaskNodeInstId(subTaskNodeInstDTO.getId());
            if (Objects.nonNull(subTaskNodeInstDTO.getId())) {
                List<NodeInstProcessVO> nodeInstConfigValueList = this.nodeInstProcessRelationDao.queryFixedNodeValueList(nodeInstConfigValueQueryDTO);
                List<NodeInstProcessVO> nodeInstDynConfigValueList = this.nodeInstProcessRelationDao.queryDynNodeValueList(nodeInstConfigValueQueryDTO);
                nodeInstConfigValueList.addAll(nodeInstDynConfigValueList);
                subTaskNodeInstVO.setNodeInstConfigValueList(nodeInstConfigValueList);
            } else {
                TaskProcessConfigQueryDTO queryDTO1 = new TaskProcessConfigQueryDTO();
                queryDTO1.setTaskNodeId(subTaskNodeInstDTO.getTaskNodeId());
                queryDTO1.setFixed(1);
                List<NodeInstProcessVO> nodeInstConfigValueList = this.taskProcessConfigDao.queryConfigElementList(queryDTO1);
                subTaskNodeInstVO.setNodeInstConfigValueList(nodeInstConfigValueList);
            }

            List<Long> nodeInstProcessRelationIdList = subTaskNodeInstVO.getNodeInstConfigValueList().stream()
                            .map(NodeInstProcessVO::getId)
                            .filter(e -> Objects.nonNull(e))
                            .collect(Collectors.toList());
            // 按照元素关联ID分组缺陷类型
            Map<String, List<DefectTypeVO>> defectTypeListMap = this.getNodeInstProcessDefectTypeList(nodeInstProcessRelationIdList);
            // 按照元素关联ID分组附件列表
            Map<String, List<TaskNodeFileVO>> taskNodeFileMap = this.queryTaskNodeFileList(nodeInstProcessRelationIdList);
            // 设置动态元素的缺陷类型
            subTaskNodeInstVO.getNodeInstConfigValueList().stream().forEach(e -> {
                if (Objects.nonNull(e.getId())) {
                    String idStr = e.getId().toString();
                    e.setTaskNodeFileList(taskNodeFileMap.get(idStr));
                    e.setDefectTypeList(defectTypeListMap.get(idStr));
                }
            });

            return ResponseDTO.succData(subTaskNodeInstVO);
        }

        return ResponseDTO.wrap(TaskResponseCodeConst.SUB_TASK_NODE_INST_NOT_FOUND);
    }

    private Map<String, List<TaskNodeFileVO>> queryTaskNodeFileList(List<Long> nodeInstProcessRelationIdList) {
        if (CollectionUtil.isEmpty(nodeInstProcessRelationIdList))
            return new HashMap<>();

        TaskNodeFileQueryDTO taskNodeFileQueryDTO = new TaskNodeFileQueryDTO();
        taskNodeFileQueryDTO.setProcessRelationIdList(nodeInstProcessRelationIdList);
        List<TaskNodeFileDTO> taskNodeFileDTOList = this.taskNodeFileDao.queryList(taskNodeFileQueryDTO);
        taskNodeFileDTOList.forEach(taskNodeFile -> {
            ResponseDTO<String> getFileUrlResp = this.fileService.getFileUrl(taskNodeFile.getFilePath(), FileServiceTypeEnum.LOCAL);
            if (getFileUrlResp.isSuccess()) {
                taskNodeFile.setUrl(getFileUrlResp.getData());
            }
        });
        return taskNodeFileDTOList.stream()
                .collect(Collectors.groupingBy(e -> e.getProcessRelationId().toString(),
                        Collectors.mapping(e -> TaskNodeFileVO.convertToTaskNodeFile(e), Collectors.toList())));
    }

    private Map<String, List<DefectTypeVO>> getNodeInstProcessDefectTypeList(List<Long> nodeInstProcessRelationIdList) {
        if (nodeInstProcessRelationIdList.size() > 0) {
            NodeInstProcessDefectQueryDTO queryDTO = new NodeInstProcessDefectQueryDTO();
            queryDTO.setProcessRelationIdList(nodeInstProcessRelationIdList);
            List<NodeInstProcessDefectDTO> list = this.nodeInstProcessDefectDao.queryByList(queryDTO);
            if (list.size() > 0)
                return list.stream()
                        .collect(Collectors.groupingBy(e -> e.getProcessRelationId().toString(),
                                Collectors.mapping(e -> DefectTypeVO.convertToDefectTypeVO(e),
                                        Collectors.toList())));
        }
        return new HashMap<>();
    }

    /**
     * 完成子任务
     * @param subTaskId
     * @return
     */
    @MethodLog
    public ResponseDTO<String> finishTask(Long subTaskId) {
        if (Objects.isNull(subTaskId))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);
        SubTaskEntity subTaskEntity = this.subTaskDao.selectById(subTaskId);
        // 任务条件校验
        this.checkTaskPreConditions(subTaskEntity);

        subTaskEntity.setStatus(TaskStatusEnum.COMPLETE.getValue());
        subTaskEntity.setCompletionTime(new Date());
        subTaskEntity.setUpdateTime(new Date());
        subTaskEntity.setUpdateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
        this.subTaskManager.finishTask(subTaskEntity);
        if (ApplicationContext.isProductEnvironment()) {
            this.aiInterfaceService.sendElectricCoreClearMessage(subTaskEntity);
        }

        return ResponseDTO.succ();
    }

    /**
     * 编辑
     * @author Tony
     * @date 2022-08-30 19:43:58
     */
    @MethodLog
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> update(SubTaskNodeInstUpdateDTO updateDTO) {
        if (Objects.isNull(updateDTO.getSubTaskId()))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);
        SubTaskEntity subTaskEntity = this.subTaskDao.selectById(updateDTO.getSubTaskId());
        if (Objects.isNull(subTaskEntity))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NOT_FOUND);
        TaskStatusEnum taskStatusEnum = BaseEnumUtil.getEnumByValue(subTaskEntity.getStatus(), TaskStatusEnum.class);
        if (!TaskStatusEnum.RUNNING.equals(taskStatusEnum)) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_STATUS_NOT_MEET_REQUIRMENT);
        }
        SubTaskNodeInstEntity subTaskNodeInstEntity = this.subTaskNodeInstDao.selectById(updateDTO.getId());
        if (Objects.isNull(subTaskNodeInstEntity))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NODE_NOT_FOUND);
        SubTaskNodeInstEntity subTaskNodeInstEntityTmp = SubTaskNodeInstEntity.convertToSubTaskNodeInstEntity(updateDTO);
        subTaskNodeInstEntity = SubTaskNodeInstEntity.copyIgnoreNullAndEmpty(subTaskNodeInstEntityTmp, subTaskNodeInstEntity);
        subTaskNodeInstDao.updateByIdIgnoreEmptyValue(subTaskNodeInstEntity);
        return ResponseDTO.succ();
    }

    /**
     * 删除
     * @author Tony
     * @date 2022-08-30 19:43:58
     */
    @MethodLog
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> deleteByIds(List<Long> idList) {
        subTaskNodeInstDao.deleteByIdList(idList);
        return ResponseDTO.succ();
    }

    /**
     * 查询全部导出对象
     * @author Tony
     * @date 2022-08-30 19:43:58
     */
    public List<SubTaskNodeInstExcelVO> queryAllExportData(SubTaskNodeInstQueryDTO queryDTO) {
        return subTaskNodeInstDao.queryAllExportData( queryDTO);
    }

    /**
     * 批量查询导出对象
     * @author Tony
     * @date 2022-08-30 19:43:58
     */
    public List<SubTaskNodeInstExcelVO> queryBatchExportData(List<Long> idList) {
        return subTaskNodeInstDao.queryBatchExportData(idList);
    }

    /**
     * 校验任务前置条件
     */
    public void checkTaskPreConditions(SubTaskEntity subTaskEntity) {
        if (Objects.isNull(subTaskEntity) || Objects.isNull(subTaskEntity.getMainTaskId()))
            throw new BusinessException(TaskResponseCodeConst.TASK_NOT_FOUND);

        TaskStatusEnum taskStatusEnum = BaseEnumUtil.getEnumByValue(subTaskEntity.getStatus(), TaskStatusEnum.class);
        if (!TaskStatusEnum.RUNNING.equals(taskStatusEnum))
            throw new BusinessException(TaskResponseCodeConst.TASK_STATUS_NOT_MEET_REQUIRMENT);
        UserBO currentUser = RequestTokenUtil.getRequestUser().getUserBO();
        if (!currentUser.getId().equals(subTaskEntity.getAssigneeId()))
            throw new BusinessException(TaskResponseCodeConst.SUB_TASK_NO_PRIVILEGE);
    }

    /**
     * 进入到下一个环节
     * @param updateDTO
     * @return
     */
    @MethodLog
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<SubTaskNodeInstVO> nextTaskNode(SubTaskNodeInstUpdateDTO updateDTO) {
        if (Objects.isNull(updateDTO.getSubTaskId()))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);

        SubTaskEntity subTaskEntity = this.subTaskDao.selectById(updateDTO.getSubTaskId());
        // 任务条件校验
        this.checkTaskPreConditions(subTaskEntity);

        // 创建当前节点实例
        TaskNodeInstQueryDTO taskNodeInstQueryDTO = new TaskNodeInstQueryDTO();
        taskNodeInstQueryDTO.setMainTaskId(subTaskEntity.getMainTaskId());
        List<TaskNodeInstEntity> taskNodeInstEntityList = this.taskNodeInstDao.queryList(taskNodeInstQueryDTO);
        TaskNodeInst currentTaskNodeInst = TaskNodeInstFactory.createTaskNodeInst(taskNodeInstEntityList, updateDTO.getTaskNodeInstId());

        // 当前的任务节点无效
        if (!currentTaskNodeInst.isValidNode()) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NODE_NOT_FOUND);
        }

        // 校验电芯编码是否存在
        if ((StrUtil.isEmpty(subTaskEntity.getElectricCoreCode()) && StrUtil.isNotEmpty(updateDTO.getElectricCoreCode())) ||
                !StrUtil.equals(subTaskEntity.getElectricCoreCode(), updateDTO.getElectricCoreCode())) {
            if (this.setOperations.isMember(CommonConst.REDIS_ELECTRIC_CORE_CODE_SET_NAME, updateDTO.getElectricCoreCode())) {
                return ResponseDTO.wrap(TaskResponseCodeConst.ELECTRIC_CORE_CODE_EXISTS);
            }
        }

        // 保存任务环节节点数据
        if (Objects.isNull(updateDTO.getId())) {
            updateDTO.setAction(TaskNodeActionEnum.NORMAL.getValue());
            ResponseDTO<SubTaskNodeInstEntity> subTaskNodeInstResp = this.taskNodeInstManager.addTaskNodeInst(updateDTO);
            if (subTaskNodeInstResp.isSuccess()) {
                SubTaskNodeInstEntity subTaskNodeInstEntity = subTaskNodeInstResp.getData();
                // 保存表单动态元素
                this.nodeInstProcessRelationService.addNodeInstProcessRelation(subTaskNodeInstEntity, updateDTO.getNodeInstConfigValueList());
                // 保存图片
                this.taskNodeFileManager.addFileList(subTaskNodeInstResp.getData(), updateDTO.getNodeInstConfigValueList());
                if (CollectionUtil.isNotEmpty(updateDTO.getDefectTypeList()))
                    this.nodeInstProcessDefectService.updateDefectType(subTaskNodeInstEntity.getSubTaskId(), subTaskNodeInstEntity.getTaskNodeInstId(), updateDTO.getDefectTypeList());
                this.subTaskManager.updateTask(subTaskEntity, updateDTO, currentTaskNodeInst.getNextTaskNodeInstEntityId());
            }
        } else {
            SubTaskNodeInstEntity subTaskNodeInstEntity = this.subTaskNodeInstDao.selectById(updateDTO.getId());
            if (Objects.isNull(subTaskNodeInstEntity))
                return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NODE_NOT_FOUND);
            updateDTO.setAction(TaskNodeActionEnum.NORMAL.getValue());
            ResponseDTO<SubTaskNodeInstEntity> updateResp = this.taskNodeInstManager.updateTaskNodeInst(subTaskNodeInstEntity, updateDTO);
            if (updateResp.isSuccess()) {
                subTaskNodeInstEntity = updateResp.getData();
                // 保存表单动态元素
                if (CollectionUtil.isNotEmpty(updateDTO.getNodeInstConfigValueList())) {
                    // 新增的表单元素
                    List<NodeInstProcessRelationUpdateDTO> newNodeProcessRelationList = updateDTO.getNodeInstConfigValueList().stream().filter(e -> Objects.isNull(e.getId())).collect(Collectors.toList());
                    // 更新的表单元素
                    List<NodeInstProcessRelationUpdateDTO> updateNodeProcessRelationList = updateDTO.getNodeInstConfigValueList().stream().filter(e -> Objects.nonNull(e.getId())).collect(Collectors.toList());
                    this.nodeInstProcessRelationService.addNodeInstProcessRelation(subTaskNodeInstEntity, newNodeProcessRelationList);
                    this.nodeInstProcessRelationService.updateNodeInstProcessRelation(subTaskNodeInstEntity, updateNodeProcessRelationList);
                    // 保存图片
                    this.taskNodeFileManager.addFileList(subTaskNodeInstEntity, updateDTO.getNodeInstConfigValueList());
                }
                if (CollectionUtil.isNotEmpty(updateDTO.getDefectTypeList()))
                    this.nodeInstProcessDefectService.updateDefectType(subTaskNodeInstEntity.getSubTaskId(), subTaskNodeInstEntity.getTaskNodeInstId(), updateDTO.getDefectTypeList());
                this.subTaskManager.updateTask(subTaskEntity, updateDTO, currentTaskNodeInst.getNextTaskNodeInstEntityId());
            }
        }

        if (null != currentTaskNodeInst.getNextTaskNodeInstEntityId()) {
            return this.queryTaskNodeInstData(updateDTO.getSubTaskId(), currentTaskNodeInst.getNextTaskNodeInstEntityId());
        }

        return ResponseDTO.wrap(TaskResponseCodeConst.NEXT_TASK_NODE_NULL);
    }

    /**
     * 进入到上一个环节
     * @param subTaskId
     * @param taskNodeInstId
     * @return
     */
    @MethodLog
    public ResponseDTO<SubTaskNodeInstVO> prevTaskNode(Long subTaskId, Long taskNodeInstId) {
        if (Objects.isNull(subTaskId))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);

        SubTaskEntity subTaskEntity = this.subTaskDao.selectById(subTaskId);
        // 任务条件校验
        this.checkTaskPreConditions(subTaskEntity);

        // 创建当前节点实例
        TaskNodeInstQueryDTO taskNodeInstQueryDTO = new TaskNodeInstQueryDTO();
        taskNodeInstQueryDTO.setMainTaskId(subTaskEntity.getMainTaskId());
        List<TaskNodeInstEntity> taskNodeInstEntityList = this.taskNodeInstDao.queryList(taskNodeInstQueryDTO);
        TaskNodeInst currentTaskNodeInst = TaskNodeInstFactory.createTaskNodeInst(taskNodeInstEntityList, taskNodeInstId);
        // 当前的任务节点无效
        if (!currentTaskNodeInst.isValidNode()) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NODE_NOT_FOUND);
        }

        if (null != currentTaskNodeInst.getPreTaskNodeInstEntity()) {
            // 查询上一个节点
            ResponseDTO<SubTaskNodeInstVO> prevSubTaskNodeInstVO = this.queryTaskNodeInstData(subTaskId, currentTaskNodeInst.getPreTaskNodeInstEntityId());
            if (prevSubTaskNodeInstVO.isSuccess() && Objects.nonNull(prevSubTaskNodeInstVO.getData())) {
                // 更新子任务当前节点为上一个节点
                subTaskEntity.setUpdateBy(RequestTokenUtil.getRequestUser().getRequestUserId());
                subTaskEntity.setUpdateTime(new Date());
                subTaskEntity.setCurrentTaskNodeInstId(currentTaskNodeInst.getPreTaskNodeInstEntityId());
                this.subTaskDao.updateByIdIgnoreEmptyValue(subTaskEntity);
                return prevSubTaskNodeInstVO;
            }
        }

        return ResponseDTO.wrap(TaskResponseCodeConst.PREV_TASK_NODE_NULL);
    }


    /**
     * 跳过当前环节
     * @param subTaskId
     * @param taskNodeInstId
     * @return
     */
    @MethodLog
    public ResponseDTO<SubTaskNodeInstVO> skipTaskNode(Long subTaskId, Long taskNodeInstId) {
        if (Objects.isNull(subTaskId))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);

        SubTaskEntity subTaskEntity = this.subTaskDao.selectById(subTaskId);
        // 任务条件校验
        this.checkTaskPreConditions(subTaskEntity);

        // 跳转到下一个节点
        TaskNodeInstQueryDTO taskNodeInstQueryDTO = new TaskNodeInstQueryDTO();
        taskNodeInstQueryDTO.setMainTaskId(subTaskEntity.getMainTaskId());
        List<TaskNodeInstEntity> taskNodeInstEntityList = this.taskNodeInstDao.queryList(taskNodeInstQueryDTO);
        TaskNodeInst currentTaskNodeInst = TaskNodeInstFactory.createTaskNodeInst(taskNodeInstEntityList, taskNodeInstId);
        // 当前的任务节点无效
        if (!currentTaskNodeInst.isValidNode()) {
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NODE_NOT_FOUND);
        }

        // 保存环节节点数据
        SubTaskNodeInstDTO subTaskNodeInstDTO = this.subTaskNodeInstDao.querySubTaskNodeInstByTaskNodeInstId(subTaskId, taskNodeInstId);
        if (Objects.isNull(subTaskNodeInstDTO.getId())) {
            // 当前节点保存空节点数据
            SubTaskNodeInstAddDTO addDTO = new SubTaskNodeInstAddDTO();
            addDTO.setSubTaskId(subTaskId);
            addDTO.setTaskNodeInstId(taskNodeInstId);
            addDTO.setAction(TaskNodeActionEnum.SKIP.getValue());

            ResponseDTO<SubTaskNodeInstEntity> subTaskNodeInstResp = this.taskNodeInstManager.addTaskNodeInst(addDTO);
            if (subTaskNodeInstResp.isSuccess()) {
                this.subTaskManager.updateTask(subTaskEntity, addDTO, currentTaskNodeInst.getNextTaskNodeInstEntityId());
            }
        } else {
            SubTaskNodeInstEntity subTaskNodeInstEntity = this.subTaskNodeInstDao.selectById(subTaskNodeInstDTO.getId());
            if (StrUtil.isEmpty(subTaskNodeInstEntity.getAction())) {
                subTaskNodeInstEntity.setAction(TaskNodeActionEnum.SKIP.getValue());
                this.subTaskNodeInstDao.updateById(subTaskNodeInstEntity);
            }
        }

        if (null != currentTaskNodeInst.getNextTaskNodeInstEntity()) {
            return this.queryTaskNodeInstData(subTaskId, currentTaskNodeInst.getNextTaskNodeInstEntityId());
        }

        return ResponseDTO.wrap(TaskResponseCodeConst.NEXT_TASK_NODE_NULL);
    }

    /**
     * 挂起子任务（保存数据）
     * @return
     */
    @MethodLog
    public ResponseDTO<Long> hangSubTask(SubTaskNodeInstUpdateDTO updateDTO) {
        if (Objects.isNull(updateDTO.getSubTaskId()))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_ID_NULL);

        SubTaskEntity subTaskEntity = this.subTaskDao.selectById(updateDTO.getSubTaskId());
        // 任务条件校验
        this.checkTaskPreConditions(subTaskEntity);

        Long id = 0L;
        if (Objects.isNull(updateDTO.getId())) {
            ResponseDTO<SubTaskNodeInstEntity> subTaskNodeInstResp = this.taskNodeInstManager.addTaskNodeInst(updateDTO);
            if (subTaskNodeInstResp.isSuccess()) {
                id = subTaskNodeInstResp.getData().getId();
                SubTaskNodeInstEntity subTaskNodeInstEntity = subTaskNodeInstResp.getData();
                // 保存表单动态元素
                this.nodeInstProcessRelationService.addNodeInstProcessRelation(subTaskNodeInstEntity, updateDTO.getNodeInstConfigValueList());
                // 保存图片
                this.taskNodeFileManager.addFileList(subTaskNodeInstResp.getData(), updateDTO.getNodeInstConfigValueList());
                if (CollectionUtil.isNotEmpty(updateDTO.getDefectTypeList()))
                    this.nodeInstProcessDefectService.updateDefectType(subTaskNodeInstEntity.getSubTaskId(), subTaskNodeInstEntity.getTaskNodeInstId(), updateDTO.getDefectTypeList());
                this.subTaskManager.updateTask(subTaskEntity, updateDTO, null);
            }
        } else {
            SubTaskNodeInstEntity subTaskNodeInstEntity = this.subTaskNodeInstDao.selectById(updateDTO.getId());
            if (Objects.isNull(subTaskNodeInstEntity))
                return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NODE_NOT_FOUND);
            if (StrUtil.isNotEmpty(subTaskNodeInstEntity.getAction())) {
                updateDTO.setAction(subTaskNodeInstEntity.getAction());
            }
            ResponseDTO<SubTaskNodeInstEntity> updateResp = this.taskNodeInstManager.updateTaskNodeInst(subTaskNodeInstEntity, updateDTO);
            if (updateResp.isSuccess()) {
                subTaskNodeInstEntity = updateResp.getData();
                // 保存表单动态元素
                if (CollectionUtil.isNotEmpty(updateDTO.getNodeInstConfigValueList())) {
                    // 新增的表单元素
                    List<NodeInstProcessRelationUpdateDTO> newNodeProcessRelationList = updateDTO.getNodeInstConfigValueList().stream().filter(e -> Objects.isNull(e.getId())).collect(Collectors.toList());
                    // 更新的表单元素
                    List<NodeInstProcessRelationUpdateDTO> updateNodeProcessRelationList = updateDTO.getNodeInstConfigValueList().stream().filter(e -> Objects.nonNull(e.getId())).collect(Collectors.toList());
                    this.nodeInstProcessRelationService.addNodeInstProcessRelation(subTaskNodeInstEntity, newNodeProcessRelationList);
                    this.nodeInstProcessRelationService.updateNodeInstProcessRelation(subTaskNodeInstEntity, updateNodeProcessRelationList);
                    // 保存图片
                    this.taskNodeFileManager.addFileList(subTaskNodeInstEntity, updateDTO.getNodeInstConfigValueList());
                }
                if (CollectionUtil.isNotEmpty(updateDTO.getDefectTypeList()))
                    this.nodeInstProcessDefectService.updateDefectType(subTaskNodeInstEntity.getSubTaskId(), subTaskNodeInstEntity.getTaskNodeInstId(), updateDTO.getDefectTypeList());
                this.subTaskManager.updateTask(subTaskEntity, updateDTO, subTaskEntity.getCurrentTaskNodeInstId());
            }
            id = updateDTO.getId();
        }

        return ResponseDTO.succData(id);
    }

    @MethodLog
    public ResponseDTO<String> getSubTaskPoleGroupFilesFromAI(GetPoleGroupFileRequestDTO getPoleGroupFileRequest) {
        if (Objects.isNull(getPoleGroupFileRequest.getSubTaskId()))
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM);
        if (StrUtil.isEmpty(getPoleGroupFileRequest.getElectricCoreCode()))
            return ResponseDTO.wrap(TaskResponseCodeConst.ELECTRIC_CORE_CODE_EMPTY);
        if (StrUtil.isEmpty(getPoleGroupFileRequest.getPoleGroupNumber()))
            return ResponseDTO.wrap(TaskResponseCodeConst.POLE_GROUP_NUMBER_EMPTY);
        SubTaskEntity subTaskEntity = this.subTaskDao.selectById(getPoleGroupFileRequest.getSubTaskId());
        if (Objects.isNull(subTaskEntity))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NOT_FOUND);

        if (getPoleGroupFileRequest.getMandatoryReGet() == JudgeEnum.YES.getValue()) {
            // 强制开启一个新的图片定时任务
            if (ApplicationContext.isProductEnvironment()) {
                this.aiInterfaceService.sendElectricCoreAddMessage(subTaskEntity);
                ResponseDTO<InterfaceLogEntity> interfaceMsgResp = this.aiInterfaceService.sendPoleGroupMessageToAI(subTaskEntity.getMainTaskId(), subTaskEntity.getId(), getPoleGroupFileRequest.getElectricCoreCode(), getPoleGroupFileRequest.getPoleGroupNumber(), InterfaceModuleEnum.SEND_ADD_POLE_GROUP_MSG_TO_AI, 0);
                if (!interfaceMsgResp.isSuccess() || JudgeEnum.NO.getValue().equals(interfaceMsgResp.getData().getResult())) {
                    return ResponseDTO.wrap(TaskResponseCodeConst.POLE_GROUP_IMAGE_MESSAGE_FAIL);
                }
            }
            this.startNewScanImageTask(subTaskEntity, getPoleGroupFileRequest);
        } else {
            InterfaceLogQueryDTO queryDTO = new InterfaceLogQueryDTO();
            queryDTO.setModule(InterfaceModuleEnum.RECEIVE_AI_IMAGE.getValue());
            queryDTO.setMainTaskId(subTaskEntity.getMainTaskId());
            queryDTO.setSubTaskId(subTaskEntity.getId());
            queryDTO.setElectricCoreCode(getPoleGroupFileRequest.getElectricCoreCode());
            queryDTO.setPoleGroupNumber(getPoleGroupFileRequest.getPoleGroupNumber());
            List<InterfaceLogEntity> scanImageInterfaceLogEntityList = this.interfaceLogDao.queryList(queryDTO);
            boolean isScanImageFinish = this.judgeImageScanFinish(scanImageInterfaceLogEntityList);
            if (isScanImageFinish)
                return ResponseDTO.wrap(TaskResponseCodeConst.POLE_GROUP_IMAGE_FINISH);
            boolean isStartNewScanTask = this.judgeIsStartNewScanTask(scanImageInterfaceLogEntityList);
            if (isStartNewScanTask) {
                if (ApplicationContext.isProductEnvironment()) {
                    this.aiInterfaceService.sendElectricCoreAddMessage(subTaskEntity);
                    ResponseDTO<InterfaceLogEntity> interfaceMsgResp = this.aiInterfaceService.sendPoleGroupMessageToAI(subTaskEntity.getMainTaskId(), subTaskEntity.getId(), getPoleGroupFileRequest.getElectricCoreCode(), getPoleGroupFileRequest.getPoleGroupNumber(), InterfaceModuleEnum.SEND_ADD_POLE_GROUP_MSG_TO_AI, 0);
                    if (!interfaceMsgResp.isSuccess() || JudgeEnum.NO.getValue().equals(interfaceMsgResp.getData().getResult())) {
                        return ResponseDTO.wrap(TaskResponseCodeConst.POLE_GROUP_IMAGE_MESSAGE_FAIL);
                    }
                }
                this.startNewScanImageTask(subTaskEntity, getPoleGroupFileRequest);
            }
        }

        return ResponseDTO.succ();
    }

    @MethodLog
    public ResponseDTO<AIImageResultVO> getSubTaskPoleGroupFiles(GetPoleGroupFileRequestDTO getPoleGroupFileRequest) {
        if (Objects.isNull(getPoleGroupFileRequest.getSubTaskId()))
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM);
        if (StrUtil.isEmpty(getPoleGroupFileRequest.getElectricCoreCode()))
            return ResponseDTO.wrap(TaskResponseCodeConst.ELECTRIC_CORE_CODE_EMPTY);
        if (StrUtil.isEmpty(getPoleGroupFileRequest.getPoleGroupNumber()))
            return ResponseDTO.wrap(TaskResponseCodeConst.POLE_GROUP_NUMBER_EMPTY);
        SubTaskEntity subTaskEntity = this.subTaskDao.selectById(getPoleGroupFileRequest.getSubTaskId());
        if (Objects.isNull(subTaskEntity))
            return ResponseDTO.wrap(TaskResponseCodeConst.TASK_NOT_FOUND);

        // 从数据库查询已经入库的文件
        List<TaskNodeFileVO> taskNodeFileList = new ArrayList<>();
        if (Objects.nonNull(getPoleGroupFileRequest.getProcessRelationId())) {
            taskNodeFileList = this.queryTaskNodeFileList(getPoleGroupFileRequest.getSubTaskNodeInstId(), getPoleGroupFileRequest.getProcessRelationId());
        }
        List<String> existsFileNameList = taskNodeFileList.stream().map(TaskNodeFileVO::getFileOrigName).collect(Collectors.toList());
        Set<String> existsFileNameSet = RhSetUtil.toSet(existsFileNameList);
        // 从文件目录查询文件
        List<TaskNodeFileVO> taskNodeFileAIList = this.getAIImageList(subTaskEntity.getTaskCode(), getPoleGroupFileRequest.getElectricCoreCode(), getPoleGroupFileRequest.getPoleGroupNumber());
        List<TaskNodeFileVO> taskNodeFileAINewList = taskNodeFileAIList.stream()
                .filter(e -> !existsFileNameSet.contains(e.getFileName()))
                .collect(Collectors.toList());
        taskNodeFileList.addAll(taskNodeFileAINewList);

        // 缺陷描述信息如果没有保存进系统中，则从AI文件描述中获取
        NodeInstProcessRelationEntity entity = this.nodeInstProcessRelationDao.selectById(getPoleGroupFileRequest.getProcessRelationId());
        String desc = Objects.isNull(entity) || StrUtil.isEmpty(entity.getDescr()) ? StrUtil.EMPTY : entity.getDescr();
        // 获取新的文件的缺陷类型
        List<DefectTypeDTO> defectTypeDTONewList = this.getAIFilesDefectType(taskNodeFileAIList, subTaskEntity.getTaskCode(), getPoleGroupFileRequest.getElectricCoreCode(), getPoleGroupFileRequest.getPoleGroupNumber());
        desc = this.combineNewDefectType(defectTypeDTONewList, desc);

        DefectTypeQueryDTO defectTypeQueryDTO = new DefectTypeQueryDTO();
        defectTypeQueryDTO.setTaskNodeId(getPoleGroupFileRequest.getTaskNodeId());

        List<DefectTypeDTO> defectTypeDTOList = this.defectTypeDao.queryByList(defectTypeQueryDTO);

        AIImageResultVO aiImageResultVO = new AIImageResultVO();
        aiImageResultVO.setTaskNodeFileList(taskNodeFileList);
        aiImageResultVO.setDefectTypeList(defectTypeDTOList);
        aiImageResultVO.setDefectTypeListNew(defectTypeDTONewList);
        aiImageResultVO.setDesc(desc);
        return ResponseDTO.succData(aiImageResultVO);
    }

    private String combineNewDefectType(List<DefectTypeDTO> defectTypeDTOList, String desc) {
        if (CollectionUtil.isEmpty(defectTypeDTOList))
            return desc;

        Map<String, Integer> defectTypeCountMap = new HashMap<>();
        String partDesc = StrUtil.EMPTY;
        if (StrUtil.isNotEmpty(desc)) {
            // 解析描述字符串，获取缺陷类型的分组统计信息
            Pattern patternWhole = PatternCache.getDefectTypeDescPatternWhole();
            Matcher matcher = patternWhole.matcher(desc);
            if (matcher.find()) {
                partDesc = StrUtil.removeAll(desc, matcher.group());
            }
            Pattern pattern = PatternCache.getDefectTypeDescPattern();
            matcher = pattern.matcher(desc);
            while (matcher.find()) {
                String defectName = matcher.group(2);
                String cntStr = matcher.group(3);
                if (StrUtil.isNotEmpty(defectName)) {
                    defectTypeCountMap.put(defectName, 0);
                    if (NumberUtils.isDigits(cntStr))
                        defectTypeCountMap.put(defectName, Integer.parseInt(cntStr));
                }
            }
        }
        // 叠加新的缺陷类型统计信息
        defectTypeDTOList.forEach(defectType -> {
            if (defectTypeCountMap.containsKey(defectType.getDefectName())) {
                Integer cnt = defectTypeCountMap.get(defectType.getDefectName());
                defectTypeCountMap.put(defectType.getDefectName(), ++cnt);
            } else {
                defectTypeCountMap.put(defectType.getDefectName(), 1);
            }
        });
        // 合并缺陷类型统计信息为固定格式字符串
        StringBuilder descBuilder = new StringBuilder();
        defectTypeCountMap.forEach((key, value) -> {
            descBuilder.append(key).append(GlobalConst.Char.ZH_L_ROUND_BRACKET)
                    .append(value)
                    .append(GlobalConst.Char.ZH_UNIT)
                    .append(GlobalConst.Char.ZH_R_ROUND_BRACKET)
                    .append(GlobalConst.Char.AIDescFileDefectTypeSplitChar);
        });
        if (StrUtil.isNotEmpty(partDesc)) {
            return descBuilder + partDesc;
        } else {
            return descBuilder.substring(0, descBuilder.length() - 1);
        }
    }

    private List<DefectTypeDTO> getAIFilesDefectType(List<TaskNodeFileVO> taskNodeFileAIList, String taskCode, String electricCoreCode, String poleGroupNumber) {
        if (CollectionUtil.isEmpty(taskNodeFileAIList))
            return ListUtil.empty();

        File descFile = new File(this.fileBasePath
                + File.separator + FileModuleTypeEnum.TASK_NODE.getPath()
                + File.separator + taskCode
                + File.separator + electricCoreCode
                + File.separator + poleGroupNumber
                + File.separator + CommonConst.DESC_FILE_NAME);
        List<AIImageDescResultDTO> aiImageResultList = this.parseDescFile(descFile);
        aiImageResultList.stream()
                .collect(Collectors.groupingBy(AIImageDescResultDTO::getDefectType, Collectors.counting()));
        List<String> defectNameList = new ArrayList<>(taskNodeFileAIList.size());
        for (TaskNodeFileVO taskNodeFileVO : taskNodeFileAIList) {
            String[] defectTypes = this.getFileDefectTypes(taskNodeFileVO.getFileName(), aiImageResultList);
            for (String defectType : defectTypes) {
                if (StrUtil.isNotEmpty(defectType)) {
                    defectNameList.add(defectType);
                }
            }
        }

        List<DefectTypeDTO>  defectTypeDTOList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(defectNameList)) {
            Map<String, DefectTypeDTO> defectTypeListMap = this.defectTypeDao.queryByDefectTypeNameList(defectNameList.stream().distinct().collect(Collectors.toList()))
                    .stream().collect(Collectors.toMap(DefectTypeDTO::getDefectName, Function.identity()));
            defectNameList.forEach(defectName -> {
                if (defectTypeListMap.containsKey(defectName))
                    defectTypeDTOList.add(defectTypeListMap.get(defectName));
            });
        }

        return defectTypeDTOList;
    }

    @Transactional(rollbackFor = Exception.class)
    public void startNewScanImageTask(SubTaskEntity subTaskEntity, GetPoleGroupFileRequestDTO getPoleGroupFileRequest) {
        Date currentDate = new Date();
        Map<String, Object> param = new HashMap<>();
        param.put("mainTaskId", subTaskEntity.getMainTaskId());
        param.put("subTaskId", subTaskEntity.getId());
        param.put("taskNodeInstId", getPoleGroupFileRequest.getTaskNodeInstId());
        param.put("electricCoreCode", subTaskEntity.getElectricCoreCode());
        param.put("poleGroupNumber", getPoleGroupFileRequest.getPoleGroupNumber());
        param.put("date", DateUtil.format(currentDate, DatePattern.PURE_DATE_FORMAT));
        InterfaceLogEntity scanImageInterfaceLogEntity = new InterfaceLogEntity();
        scanImageInterfaceLogEntity.setModule(InterfaceModuleEnum.RECEIVE_AI_IMAGE.getValue());
        scanImageInterfaceLogEntity.setContent(InterfaceModuleEnum.RECEIVE_AI_IMAGE.getDesc());
        scanImageInterfaceLogEntity.setMainTaskId(subTaskEntity.getMainTaskId());
        scanImageInterfaceLogEntity.setSubTaskId(subTaskEntity.getId());
        scanImageInterfaceLogEntity.setElectricCoreCode(getPoleGroupFileRequest.getElectricCoreCode());
        scanImageInterfaceLogEntity.setPoleGroupNumber(getPoleGroupFileRequest.getPoleGroupNumber());
        scanImageInterfaceLogEntity.setParam(param);
        scanImageInterfaceLogEntity.setStatus(JudgeEnum.NO.getValue().toString());
        scanImageInterfaceLogEntity.setRevision(0);
        scanImageInterfaceLogEntity.setCreateTime(new Date());
        this.interfaceLogDao.insert(scanImageInterfaceLogEntity);
        this.aiInterfaceService.startScanAIImageTask(scanImageInterfaceLogEntity);
    }

    private boolean judgeIsStartNewScanTask(List<InterfaceLogEntity> interfaceLogEntityList) {
        return interfaceLogEntityList.stream().allMatch(e -> JudgeEnum.YES.getValue().toString().equals(e.getStatus()))
                    || interfaceLogEntityList.size() == 0;
    }

    private boolean judgeImageScanFinish(List<InterfaceLogEntity> interfaceLogEntityList) {
        return interfaceLogEntityList.size() > 0 && interfaceLogEntityList.stream().allMatch(e -> JudgeEnum.YES.getValue().toString().equals(e.getStatus()));
    }

    private List<TaskNodeFileVO> getAIImageList(String taskCode, String electricCoreCode, String poleGroupNumber) {
        String subPath = FileModuleTypeEnum.TASK_NODE.getPath()
                + File.separator + taskCode
                + File.separator + electricCoreCode
                + File.separator + poleGroupNumber;
        File folder = new File(this.fileBasePath + File.separator + subPath);
        log.debug("getAIImageList folder {}", folder);

        if (folder.exists() && folder.isDirectory()) {
            // 读取描述文件
            File[] images = folder.listFiles(file -> file.getName().contains(CommonConst.THUMBNAIL_PREFIX));
            if (Objects.nonNull(images) && images.length > 0) {
                List<TaskNodeFileVO> taskNodeFileList = new ArrayList<>();
                for (File image : images) {
                    TaskNodeFileVO taskNodeFile = new TaskNodeFileVO();
                    taskNodeFile.setModuleType("1");
                    taskNodeFile.setModuleId("1");
                    taskNodeFile.setFileLocationType(FileServiceTypeEnum.LOCAL.getValue());
                    taskNodeFile.setFileOrigName(image.getName());
                    taskNodeFile.setFileName(image.getName());
                    taskNodeFile.setFilePath(subPath + File.separator + image.getName());
                    taskNodeFile.setFileSize(image.length());
                    taskNodeFile.setSource(FileSourceEnum.AI.getValue());
                    ResponseDTO<String> getUrlResp = this.fileService.getFileUrl(taskNodeFile.getFilePath(), FileServiceTypeEnum.LOCAL);
                    if (getUrlResp.isSuccess()) {
                        taskNodeFile.setUrl(getUrlResp.getData());
                    }
                    taskNodeFileList.add(taskNodeFile);
                }
                log.debug("getAIImageList fileList {}", taskNodeFileList);

                return taskNodeFileList;
            }
        }

        return new ArrayList<>();
    }

    private String[] getFileDefectTypes(String fileName, List<AIImageDescResultDTO> aiImageDescResultDTOList) {
        for (AIImageDescResultDTO aiImageDescResultDTO : aiImageDescResultDTOList) {
            if (fileName.equals(CommonConst.THUMBNAIL_PREFIX + aiImageDescResultDTO.getFileName())) {
                if (StrUtil.isNotEmpty(aiImageDescResultDTO.getDefectType()))
                    return aiImageDescResultDTO.getDefectType().split(GlobalConst.Char.AIDescFileDefectTypeSplitChar);
            }
        }

        return new String[0];
    }

    private List<AIImageDescResultDTO> parseDescFile(File descFile) {
        if (Objects.isNull(descFile))
            return new ArrayList<>();

        if (descFile.exists()) {
            String content = FileUtil.readString(descFile, Charset.forName(CharsetUtil.UTF_8));
            return JSON.parseObject(content, AIImageDescDTO.class).getResult();
        }

        return new ArrayList<>();
    }

    @MethodLog
    public ResponseDTO<List<TaskNodeFileVO>> getTaskNodeFileList(Long subTaskNodeInstId, Long processRelationId) {
        return ResponseDTO.succData(this.queryTaskNodeFileList(subTaskNodeInstId, processRelationId));
    }


    public List<TaskNodeFileVO> queryTaskNodeFileList(Long subTaskNodeInstId, Long processRelationId) {
        if (Objects.isNull(subTaskNodeInstId) || Objects.isNull(processRelationId))
            return new ArrayList<>();

        TaskNodeFileQueryDTO taskNodeFileQueryDTO = new TaskNodeFileQueryDTO();
        taskNodeFileQueryDTO.setSubTaskNodeInstId(subTaskNodeInstId);
        taskNodeFileQueryDTO.setProcessRelationId(processRelationId);
        List<TaskNodeFileDTO> taskNodeFileDTOList = this.taskNodeFileDao.queryList(taskNodeFileQueryDTO);
        taskNodeFileDTOList.forEach(taskNodeFile -> {
            ResponseDTO<String> getFileUrlResp = this.fileService.getFileUrl(taskNodeFile.getFilePath(), FileServiceTypeEnum.LOCAL);
            if (getFileUrlResp.isSuccess()) {
                taskNodeFile.setUrl(getFileUrlResp.getData());
            }
        });
        List<TaskNodeFileVO> taskNodeFileVOList = TaskNodeFileList.convertDTOToTaskNodeFileVOList(taskNodeFileDTOList);
        return taskNodeFileVOList;
    }
}
